using System;
using System.Collections;
using System.Net;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;

using WoWAddonRefresh.Entities;
using System.Web;

using JEvaluator;
using System.Collections.Generic;
using System.Xml.Serialization;

using System.Data.Linq;
using System.Linq;
using System.Linq.Expressions;

namespace WoWAddonRefresh {
    public class Request {
        public Request() {
            //cookieContainer = new CookieContainer();
            //request = (HttpWebRequest)WebRequest.Create(WoWAddonRefresh.Constants.URL_WoWInterface);
            //SetRequestDefaults();
        }

        public Request(CookieContainer cc) {
            //cookieContainer = cc;
            //request = (HttpWebRequest)WebRequest.Create(WoWAddonRefresh.Constants.URL_WoWInterface);
            //SetRequestDefaults();
        }

        private void SetRequestDefaults() {
            // request.UseDefaultCredentials = true;
            // request.Accept = "*/*";
            // request.SendChunked = true;
            
            request.AllowAutoRedirect = true;
            request.Referer = WoWAddonRefresh.Constants.URL_WoWInterface;
            ServicePointManager.Expect100Continue = false;
            request.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0;)";
            request.KeepAlive = true;
            request.Timeout = 60000;


            if (response != null) {
                request.CookieContainer = cookieContainer != null ? cookieContainer : new CookieContainer();
                if (response.Headers != null) {
                    foreach (string key in response.Headers.Keys) {
                        if (key == "Set-Cookie") {
                            string value = response.Headers[key];
                            string result = "";
                            foreach (string item in value.Split(new char[] { ';' })) {
                                string name = item.Split(new char[] { '=' })[0].Trim();
                                // string val = item.Split(new char[] { '=' })[1].Trim();
                                // request.CookieContainer.Add(new Cookie(name, val, "/"));
                                if (name != "path" && name != "expires") {
                                    result += (item + ";");
                                }
                            }
                            request.Headers.Set("Cookie", result);
                        }
                        else {
                            //try {
                            //    request.Headers.Set(key, response.Headers[key]);
                            //}
                            //catch {
                            //}
                        }

                    }
                }
            }

            // request.Headers = headerCollection != null ? headerCollection : new WebHeaderCollection();
            //string proxyAddress = "proxy";
            //if (proxyAddress.Length > 0) {
            //    req.Proxy = new WebProxy(proxyAddress, true);
            //    req.Proxy.Credentials = CredentialCache.DefaultCredentials;
            //}

        }

        private CookieContainer cookieContainer = null;
        // private WebHeaderCollection headerCollection = null;

        private HttpWebRequest request = null;
        private HttpWebResponse response = null;
        private string sessionID = "";
        // we need download not more than 50 items at 30 sec (curse-gaming.com restriction)
        private DownloadSpanCollection downloadSpans = new DownloadSpanCollection();

        #region JScript


        private string JScript = @"
            package vBulletin
            {
                class Security
                {
                    var hexcase = 0;  
                    var b64pad  = ''; 
                    var chrsz   = 8;  

                    function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
                    function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
                    function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
                    function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
                    function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
                    function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }

                    function core_md5(x, len)
                    {
                      x[len >> 5] |= 0x80 << ((len) % 32);
                      x[(((len + 64) >>> 9) << 4) + 14] = len;

                      var a =  1732584193;
                      var b = -271733879;
                      var c = -1732584194;
                      var d =  271733878;

                      for(var i = 0; i < x.length; i += 16)
                      {
                        var olda = a;
                        var oldb = b;
                        var oldc = c;
                        var oldd = d;

                        a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
                        d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
                        c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
                        b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
                        a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
                        d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
                        c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
                        b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
                        a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
                        d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
                        c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
                        b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
                        a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
                        d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
                        c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
                        b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

                        a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
                        d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
                        c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
                        b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
                        a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
                        d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
                        c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
                        b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
                        a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
                        d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
                        c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
                        b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
                        a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
                        d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
                        c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
                        b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

                        a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
                        d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
                        c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
                        b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
                        a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
                        d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
                        c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
                        b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
                        a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
                        d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
                        c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
                        b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
                        a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
                        d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
                        c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
                        b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

                        a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
                        d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
                        c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
                        b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
                        a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
                        d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
                        c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
                        b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
                        a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
                        d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
                        c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
                        b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
                        a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
                        d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
                        c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
                        b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

                        a = safe_add(a, olda);
                        b = safe_add(b, oldb);
                        c = safe_add(c, oldc);
                        d = safe_add(d, oldd);
                      }
                      return Array(a, b, c, d);

                    }

                    function md5_cmn(q, a, b, x, s, t)
                    {
                      return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
                    }
                    function md5_ff(a, b, c, d, x, s, t)
                    {
                      return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
                    }
                    function md5_gg(a, b, c, d, x, s, t)
                    {
                      return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
                    }
                    function md5_hh(a, b, c, d, x, s, t)
                    {
                      return md5_cmn(b ^ c ^ d, a, b, x, s, t);
                    }
                    function md5_ii(a, b, c, d, x, s, t)
                    {
                      return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
                    }

                    function core_hmac_md5(key, data)
                    {
                      var bkey = str2binl(key);
                      if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);

                      var ipad = Array(16), opad = Array(16);
                      for(var i = 0; i < 16; i++)
                      {
                        ipad[i] = bkey[i] ^ 0x36363636;
                        opad[i] = bkey[i] ^ 0x5C5C5C5C;
                      }

                      var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
                      return core_md5(opad.concat(hash), 512 + 128);
                    }

                    function safe_add(x, y)
                    {
                      var lsw = (x & 0xFFFF) + (y & 0xFFFF);
                      var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
                      return (msw << 16) | (lsw & 0xFFFF);
                    }

                    function bit_rol(num, cnt)
                    {
                      return (num << cnt) | (num >>> (32 - cnt));
                    }

                    function str2binl(str)
                    {
                      var bin = new Array();
                      var mask = (1 << chrsz) - 1;
                      for(var i = 0; i < str.length * chrsz; i += chrsz)
                        bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
                      return bin;
                    }

                    function binl2str(bin)
                    {
                      var str = '';
                      var mask = (1 << chrsz) - 1;
                      for(var i = 0; i < bin.length * 32; i += chrsz)
                        str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
                      return str;
                    }

                    function binl2hex(binarray)
                    {
                      var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef';
                      var str = '';
                      for(var i = 0; i < binarray.length * 4; i++)
                      {
                        str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
                               hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
                      }
                      return str;
                    }

                    function binl2b64(binarray)
                    {
                      var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
                      var str = '';
                      for(var i = 0; i < binarray.length * 4; i += 3)
                      {
                        var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16) | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
                        for(var j = 0; j < 4; j++)
                        {
                          if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
                          else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
                        }
                      }
                      return str;
                    }

                    function str_to_ent(str)
                    {
	                    var result = '';
	                    var i;

	                    for (i = 0; i < str.length; i++)
	                    {
		                    var c = str.charCodeAt(i);
		                    var tmp = '';

		                    if (c > 255)
		                    {

			                    while (c >= 1)
			                    {
				                    tmp = '0123456789' . charAt(c % 10) + tmp;
				                    c = c / 10;
			                    }

			                    if (tmp == '')
			                    {
				                    tmp = '0';
			                    }
			                    tmp = '#' + tmp;
			                    tmp = '&' + tmp;
			                    tmp = tmp + ';';

			                    result += tmp;
		                    }
		                    else
		                    {
			                    result += str.charAt(i);
		                    }
	                    }
	                    return result;
                    }

                    function trim(s)
                    {
	                    while (s.substring(0, 1) == ' ')
	                    {
		                    s = s.substring(1, s.length);
	                    }
	                    while (s.substring(s.length-1, s.length) == ' ')
	                    {
		                    s = s.substring(0, s.length-1);
	                    }
	                    return s;
                    }

                    function md5hash(input)
                    {
	                    return hex_md5(str_to_ent(input)) + '|' + hex_md5(trim(input));
                    }
                }
            }
        ";

        #endregion JScript
        public FormMain mainForm;
        public FormMain MainForm {
            set {
                mainForm = value;
            }
        }

        private int PAGECOUNT = 1;

        public string GetFullHTML() {
            string result = GetInfoHTML(WoWAddonRefresh.Constants.URL_WoWInterface);

            if (PAGECOUNT > 1) {
                for (int page = 2; page <= PAGECOUNT; page++) {
                    result += GetInfoHTML(WoWAddonRefresh.Constants.URL_WoWInterface + page + "/sort-by/name/-date/");
                }
            }
            // @"http://feeds.curse.com/favorites/48/135964.xml"


            //StreamWriter writer = new StreamWriter("temp_addons.html", false);
            //writer.WriteLine(result);
            //writer.Flush();
            //writer.Close();

            return result;
        }

        public string ParsePages(string html) {
            string result = "";
            string tempString = html;
            string rowBegining = "<a";
            string rowEnd = "</a>";
            int rowEnd_Length = rowEnd.Length;
            while (tempString.IndexOf(rowEnd) > 0) {
                int start = tempString.IndexOf(rowBegining);
                if (start < 0) break;
                int length = tempString.IndexOf(rowEnd, start) + rowEnd_Length - start;
                if (length > 0) {
                    string page = tempString.Substring(start, length);
                    tempString = tempString.Replace(page, "");
                    page = Parser.ReplaceHTML(page).Trim();
                    result += page;
                }
                else {
                    Console.WriteLine(tempString);
                    return result;
                }
            }
            return result;
        }

        public string GetInfoHTML(string URL) {
            byte[] buffer = new byte[8192];
            StringBuilder stringBuilder = new StringBuilder();

            // prepare the web page we will be asking for
            request = (HttpWebRequest)HttpWebRequest.Create(URL);
            SetRequestDefaults();
            request.CookieContainer = cookieContainer;
            //request.Method = "GET";
            //request.Method = "POST";
            //request.ContentType = "application/x-www-form-urlencoded";

            //string postData = "sortby=name&orderby=asc&perpage=100";
            //ASCIIEncoding encoding = new ASCIIEncoding();
            //byte[] data = encoding.GetBytes(postData);

            //request.ContentLength = data.Length;
            //Stream stream = request.GetRequestStream();
            //stream.Write(data, 0, data.Length);
            //stream.Close();

            // execute the request
            //try {

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            //}
            //catch {}

            if ((response.StatusCode == HttpStatusCode.Found) ||
                (response.StatusCode == HttpStatusCode.Redirect) ||
                (response.StatusCode == HttpStatusCode.Moved) ||
                (response.StatusCode == HttpStatusCode.MovedPermanently)) {
                // Get new location and call recursively
                WebHeaderCollection headers = response.Headers;
                request = (HttpWebRequest)WebRequest.Create(headers["location"]);
                SetRequestDefaults();
                response = (HttpWebResponse)request.GetResponse();
            }

            // we will read data via the response stream
            Stream resStream = response.GetResponseStream();
            string tempString = null;
            int count = 0;
            do {
                // fill the buffer with data
                count = resStream.Read(buffer, 0, buffer.Length);
                // make sure we read some data
                if (count != 0) {
                    // translate from bytes to ASCII text
                    tempString = Encoding.ASCII.GetString(buffer, 0, count);
                    // continue building the string
                    stringBuilder.Append(tempString);
                }
            }
            while (count > 0); // any more data to read?
            // print out page source

            //StreamWriter writer = new StreamWriter("temp.html", false);
            //writer.WriteLine(stringBuilder.ToString());
            //writer.Flush();
            //writer.Close();

            string result = stringBuilder.ToString();
            if (PAGECOUNT == 1) {
                int s = result.IndexOf("Page 1 of ");
                if (s > -1) {
                    int f = result.IndexOf("</div>", s);
                    if (f > -1) {
                        string toParse = result.Substring((s + 10), (f - (s + 10)));
                        int.TryParse(toParse, out PAGECOUNT);
                    }
                }
            }
            // string search_begining = "<div class=\"subhead\">List of your addons</div>This system is built to easily follow your addons.<br><br>";
            string search_begining = "<tr class=\"row1";
            string search_ending = "</table>";
            int start = result.IndexOf(search_begining) /*+ search_begining.Length*/;
            int length = result.IndexOf(search_ending, start) - start;
            /*  */
            // writer = new StreamWriter("result1.html", false);
            //string html_begin = "<html><head><link rel=\"stylesheet\" type=\"text/css\" href=\"http://65.98.12.220/css/main.css\" /><link rel=\"stylesheet\" type=\"text/css\" href=\"http://65.98.12.220/css/3.css\" /></head><body>";
            //string html_end = "</body></html>";
            //writer.WriteLine(html_begin + result + html_end);
            //writer.Flush();
            //writer.Close();

            result = result.Substring(start, length);

            //writer = new StreamWriter("result2.html", false);
            //writer.WriteLine(html_begin + result + html_end);
            //writer.Flush();
            //writer.Close();

            return result;
        }

        public string GetHTML(string URL) {
            byte[] buffer = new byte[8192];
            StringBuilder stringBuilder = new StringBuilder();

            // prepare the web page we will be asking for
            request = (HttpWebRequest)WebRequest.Create(URL);
            SetRequestDefaults();
            // request.CookieContainer = cookieContainer;
            // request.Headers = headerCollection;

            // execute the request
            //try {
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            //}
            //catch {}

            if ((response.StatusCode == HttpStatusCode.Found) ||
                (response.StatusCode == HttpStatusCode.Redirect) ||
                (response.StatusCode == HttpStatusCode.Moved) ||
                (response.StatusCode == HttpStatusCode.MovedPermanently)) {
                // Get new location and call recursively
                WebHeaderCollection headers = response.Headers;
                request = (HttpWebRequest)WebRequest.Create(headers["location"]);
                SetRequestDefaults();
                response = (HttpWebResponse)request.GetResponse();
            }

            // we will read data via the response stream
            Stream resStream = response.GetResponseStream();
            string tempString = null;
            int count = 0;
            do {
                // fill the buffer with data
                count = resStream.Read(buffer, 0, buffer.Length);
                // make sure we read some data
                if (count != 0) {
                    // translate from bytes to ASCII text
                    tempString = Encoding.ASCII.GetString(buffer, 0, count);
                    // continue building the string
                    stringBuilder.Append(tempString);
                }
            }
            while (count > 0); // any more data to read?

            // print out page source
            //StreamWriter writer = new StreamWriter("html.html", false);
            //writer.WriteLine(stringBuilder.ToString());
            //writer.Flush();
            //writer.Close();

            return stringBuilder.ToString();
        }

        private void SaveHTML(string html) {
            StreamWriter writer = new StreamWriter("html.html");
            writer.Write(html);
            writer.Flush();
            writer.Close();
        }

        public string GetAddonHTML(ref Addon addon) {
            string URL = addon.NameLink;
            string result = GetHTML(Constants.URL_WoWInterface_Download + URL);
            // SaveHTML(result);
            try {
                string descriptionBegining = "<script type=\"text/javascript\"> vbmenu_register(\"rate_file\"); </script>";
                int descriptionStart = result.IndexOf(descriptionBegining) + descriptionBegining.Length;
                int descriptionLength = result.IndexOf("</td>", descriptionStart) - descriptionStart;
                string description = result.Substring(descriptionStart, descriptionLength).Replace("<br>", "\n").Replace("</br>", "\n").Trim();


                string changesBegining = "<div class=\"panelsurround\"><div class=\"panel\">";
                int changesStart = result.IndexOf(changesBegining, descriptionStart + descriptionLength) + changesBegining.Length;
                int changesLength = result.IndexOf("</div>", changesStart) - changesStart;
                string changes = result.Substring(changesStart, changesLength).Replace("<br>", "\n").Replace("</br>", "\n").Trim();

                addon.Description = HttpUtility.HtmlDecode(Parser.ReplaceHTML(description)).Trim();
                addon.Changes = HttpUtility.HtmlDecode(Parser.ReplaceHTML(changes)).Trim();
            }
            catch {
            }

            //StreamWriter writer = new StreamWriter("result_addoninfo.html", false);
            //string html_begin = "<html><head><link rel=\"stylesheet\" href=\"style.css\"></head><body>";
            //string html_end = "</body></html>";
            //writer.WriteLine(html_begin + result + html_end);
            //writer.Flush();
            //writer.Close();

            return result;
        }

        public static string GetFilename(HttpWebResponse ws) {
            string val = "";
            string[] headers = ws.Headers.GetValues("Content-Disposition");
            if (headers == null) return null;
            foreach (string header in headers) {
                val += header;
            }
            int start = val.IndexOf("filename=\"");
            if (start > 0) {
                start = start + 10;
                int length = val.IndexOf("\"", start) - start;
                if (length > 0) {
                    string result = val.Substring(start, length);
                    return result;
                }
                else return null;
            }
            else return null;
        }

        public void Logout() {
            cookieContainer = new CookieContainer();
            LOGEDIN = false;
        }

        private bool logedin = false;
        public bool LOGEDIN {
            get {
                return logedin;
            }
            set {
                logedin = value;
            }
        }

        public string LoginVBulletin(Credentials credentials, string url) {
            // string data = PrepareVBulletinGetData(credentials);
            // string html = ReceiveGetHTML(Constants.URL_WoWInterface_Login + "&" + data, credentials);
            byte[] data = PrepareVBulletinPostData(credentials);
            string html = ReceivePostHTML(Constants.URL_WoWInterface_Login, data, credentials);
            // <meta http-equiv="Refresh" content="0; URL=http://www.wowinterface.com/downloads/filecpl.php?action=favorite&s=5a42af2a2b7045d81f64d24455334c82&" />
            if (html.Contains("Thank you for logging in")) return Parser.GetURL(html);
            else return null;
        }

        private byte[] PrepareVBulletinPostData(Credentials credentials) {
            /*<!-- login form -->
            <form action="/forums/login.php?do=login" 
             * method="post" 
             * onsubmit="md5hash(vb_login_password, vb_login_md5password, vb_login_md5password_utf, 0)">
            <script type="text/javascript" src="http://s.wowinterface.com/clientscript/vbulletin_md5.js?v=368"></script>
            <input type="text" class="bginput" style="font-size: 11px" name="vb_login_username" id="navbar_username" size="10" accesskey="u" tabindex="101" value="User Name" onfocus="if (this.value == 'User Name') this.value = '';" />
            <input type="checkbox" name="cookieuser" value="1" tabindex="103" id="cb_cookieuser_navbar" accesskey="c" />
            <input type="password" class="bginput" style="font-size: 11px" name="vb_login_password" id="navbar_password" size="10" tabindex="102" />
            <input type="submit" class="button" value="Log in" tabindex="104" title="Enter your username and password in the boxes provided to login, or click the 'register' button to create a profile for yourself." accesskey="s" />
            <input type="hidden" name="s" value="" />
            <input type="hidden" name="do" value="login" />		
            <input type="hidden" name="vb_login_md5password" />
            <input type="hidden" name="vb_login_md5password_utf" />
            </form>
            <!-- / login form -->*/

            Evaluator eval = new Evaluator(JScript, "vBulletin.Security");
            // function md5hash(input, output_html, output_utf, skip_empty)
            object[] obj = new object[] { credentials.Password };
            string result = eval.Evaluate(obj, "md5hash").ToString();
            // MessageBox.Show(result);
            string vb_login_password = "";
            string vb_login_md5password = result.Substring(0, result.IndexOf("|"));
            string vb_login_md5password_utf = result.Substring(result.IndexOf("|") + 1);
            cookieContainer = new CookieContainer();
            // string url = "http://forums.curse-gaming.com/login.php?cookieuser=1&s=&&do=login&vb_login_username=" + username + "&vb_login_password=" + vb_login_password + "&vb_login_md5password=" + vb_login_md5password + "&vb_login_md5password_utf=" + vb_login_md5password_utf + "";
            // string url = "http://forums.curse-gaming.com/login.php";
            // string url = "http://wow.curse-gaming.com/en/accounts/login/";
            // string postData = "s=&do=login&cookieuser=1&action=login&vb_login_username=" + credentials.Username + "&password=" + vb_login_password + "&vb_login_md5password=" + vb_login_md5password + "&vb_login_md5password_utf=" + vb_login_md5password_utf + "";
            string postData = "s=&do=login&cookieuser=1&action=login&vb_login_username=" + credentials.Username + "&password=" + vb_login_password + "&vb_login_md5password=" + vb_login_md5password + "&vb_login_md5password_utf=" + vb_login_md5password_utf + "";
            // string postData = "cookieuser=1&next=123&username=" + username + "&password=" + password + "";


            // string postData = "cookieuser=1&do=login&action=login&vb_login_username=" + credentials.Username + "&vb_login_password=" + credentials.Password + "&navbar_username=" + credentials.Username + "&navbar_password=" + credentials.Password + "&vb_login_md5password=&vb_login_md5password_utf=&s=";
            // UTF8Encoding encoding = new UTF8Encoding();
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] data = encoding.GetBytes(postData);
            return data;
        }

        private string PrepareVBulletinGetData(Credentials credentials) {
            /*<!-- login form -->
            <form action="/forums/login.php?do=login" method="post" onsubmit="md5hash(vb_login_password, vb_login_md5password, vb_login_md5password_utf, 0)">
            <script type="text/javascript" src="http://s.wowinterface.com/clientscript/vbulletin_md5.js?v=368"></script>
            <table cellpadding="0" cellspacing="3" border="0">
            <tr>
                <td nowrap="nowrap" class="smallfont"><label for="navbar_username">User Name</label></td>
                                <td><input type="text" class="bginput" style="font-size: 11px" name="vb_login_username" id="navbar_username" size="10" accesskey="u" tabindex="101" value="User Name" onfocus="if (this.value == 'User Name') this.value = '';" /></td>
                <td class="smallfont" colspan="2" nowrap="nowrap"><label for="cb_cookieuser_navbar"><input type="checkbox" name="cookieuser" value="1" tabindex="103" id="cb_cookieuser_navbar" accesskey="c" />Remember Me?</label></td>
            </tr>
            <tr>
                <td nowrap="nowrap" class="smallfont"><label for="navbar_password">Password</label></td>
                <td><input type="password" class="bginput" style="font-size: 11px" name="vb_login_password" id="navbar_password" size="10" tabindex="102" /></td>
                <td><input type="submit" class="button" value="Log in" tabindex="104" title="Enter your username and password in the boxes provided to login, or click the 'register' button to create a profile for yourself." accesskey="s" /></td>
            </tr>
            </table>
            <input type="hidden" name="s" value="" />
            <input type="hidden" name="do" value="login" />		
            <input type="hidden" name="vb_login_md5password" />
            <input type="hidden" name="vb_login_md5password_utf" />
            </form>
            <!-- / login form -->*/

            Evaluator eval = new Evaluator(JScript, "vBulletin.Security");
            // function md5hash(input, output_html, output_utf, skip_empty)
            object[] obj = new object[] { credentials.Password };
            string result = eval.Evaluate(obj, "md5hash").ToString();
            // MessageBox.Show(result);
            string vb_login_password = "";
            string vb_login_md5password = result.Substring(0, result.IndexOf("|"));
            string vb_login_md5password_utf = result.Substring(result.IndexOf("|") + 1);
            cookieContainer = new CookieContainer();
            // string url = "http://forums.curse-gaming.com/login.php?cookieuser=1&s=&&do=login&vb_login_username=" + username + "&vb_login_password=" + vb_login_password + "&vb_login_md5password=" + vb_login_md5password + "&vb_login_md5password_utf=" + vb_login_md5password_utf + "";
            // string url = "http://forums.curse-gaming.com/login.php";
            // string url = "http://wow.curse-gaming.com/en/accounts/login/";
            string postData = "cookieuser=1&action=login&username=" + credentials.Username + "&password=" + vb_login_password + "&vb_login_md5password=" + vb_login_md5password + "&vb_login_md5password_utf=" + vb_login_md5password_utf + "";
            // string postData = "cookieuser=1&next=123&username=" + username + "&password=" + password + "";


            // string postData = "cookieuser=1&do=login&action=login&vb_login_username=" + credentials.Username + "&vb_login_password=" + credentials.Password + "&navbar_username=" + credentials.Username + "&navbar_password=" + credentials.Password + "&vb_login_md5password=&vb_login_md5password_utf=&s=";
            // UTF8Encoding encoding = new UTF8Encoding();
            // byte[] data = encoding.GetBytes(postData);
            // return data;
            return postData;
        }

        public List<Addon> GetWoWInterfaceAddons(string url, Credentials credentials) {
            string html = ReceiveGetHTML(url, credentials);

            int a = html.IndexOf("http://www.wowinterface.com/rss/myfav-");
            a = html.IndexOf("<tr", a + 1);
            a = html.IndexOf("<tr", a + 1);
            int z = html.IndexOf("</table>", a);
            html = html.Substring(a, z - a);

            return Parser.ParseHTML(html);
            // return new List<Addon>();
        }

        //XmlSerializer xmlSerializer = new XmlSerializer(typeof(Credentials));
        //            credentials = (Credentials)xmlSerializer.Deserialize(reader);
        //            reader.Close();

        //StreamWriter writer = new StreamWriter(isoStream);
        //    XmlSerializer xmlSerializer = new XmlSerializer(typeof(Credentials));
        //    xmlSerializer.Serialize(writer, credentials);
        //    writer.Close();

        private void GetCookies(Credentials credentials) {
            try {
                StringReader reader = new StringReader(credentials.Cookies);
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(CookieContainer));
                cookieContainer = (CookieContainer)xmlSerializer.Deserialize(reader);
                reader.Close();
            }
            catch { }
        }

        private void SetCookies(Credentials credentials) {
            try {
                StringBuilder stringBuilder = new StringBuilder();
                StringWriter writer = new StringWriter(stringBuilder);
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(CookieContainer));
                xmlSerializer.Serialize(writer, cookieContainer);
                writer.Close();
                credentials.Cookies = stringBuilder.ToString();
            }
            catch { }
        }

        public string ReceivePostHTML(string url, byte[] data, Credentials credentials) {

            byte[] buffer = new byte[8192];
            request = (HttpWebRequest)HttpWebRequest.Create(url);
            SetRequestDefaults();

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            Stream stream = request.GetRequestStream();
            stream.Write(data, 0, data.Length);
            stream.Close();

            response = (HttpWebResponse)request.GetResponse();

            Stream resStream = response.GetResponseStream();

            if (request.HaveResponse) {
                foreach (Cookie cookie in response.Cookies) {
                    cookie.Expires = cookie.Expires.Date <= System.DateTime.Now.Date ? System.DateTime.Now.AddYears(1) : cookie.Expires;
                    cookie.Expired = false;
                    cookie.Discard = false;
                    cookieContainer.Add(cookie);
                }

                // Next is redirection
                if ((response.StatusCode == HttpStatusCode.Found) ||
                    (response.StatusCode == HttpStatusCode.Redirect) ||
                    (response.StatusCode == HttpStatusCode.Moved) ||
                    (response.StatusCode == HttpStatusCode.MovedPermanently)) {
                    // Get new location and call recursively
                    WebHeaderCollection headers = response.Headers;
                    request = (HttpWebRequest)WebRequest.Create(headers["Location"]);

                    HttpWebResponse redirectedResponse = (HttpWebResponse)request.GetResponse();
                    sessionID = request.RequestUri.Query.Replace("?", "");
                    resStream = redirectedResponse.GetResponseStream();
                    // return SendRequestTo(requestBytes,new Uri(headers["location"]),credential); 
                }
            }

            StringBuilder stringBuilder = new StringBuilder();
            string tempString = null;
            int count = 0;
            do {
                // fill the buffer with data
                count = resStream.Read(buffer, 0, buffer.Length);
                // make sure we read some data
                if (count != 0) {
                    // translate from bytes to ASCII text
                    tempString = Encoding.ASCII.GetString(buffer, 0, count);
                    // continue building the string
                    stringBuilder.Append(tempString);
                }
            }

            while (count > 0); // any more data to read?

            string html = stringBuilder.ToString();
            WriteDebugHTML(html);
            return html;
        }

        public void WriteDebugHTML(string html) {
            StreamWriter writer = new StreamWriter("debug.html");
            writer.Write(html);
            writer.Flush();
            writer.Close();
        }


        public string ReceiveGetHTML(string url, Credentials credentials) {
            GetCookies(credentials);

            request = (HttpWebRequest)HttpWebRequest.Create(url);
            SetRequestDefaults();
            request.CookieContainer = cookieContainer;

            response = (HttpWebResponse)request.GetResponse();
            // response.Cookies = request.CookieContainer.GetCookies(request.RequestUri);


            Stream resStream = response.GetResponseStream();

            if (request.HaveResponse) {
                // headerCollection = response.Headers;

                foreach (Cookie cookie in response.Cookies) {
                    cookie.Expires = cookie.Expires.Date <= System.DateTime.Now.Date ? System.DateTime.Now.AddYears(1) : cookie.Expires;
                    cookie.Expired = false;
                    cookie.Discard = false;
                    cookieContainer.Add(cookie);
                }

                SetCookies(credentials);

                // Next is redirection
                if ((response.StatusCode == HttpStatusCode.Found) ||
                    (response.StatusCode == HttpStatusCode.Redirect) ||
                    (response.StatusCode == HttpStatusCode.Moved) ||
                    (response.StatusCode == HttpStatusCode.MovedPermanently)) {
                    // Get new location and call recursively
                    WebHeaderCollection headers = response.Headers;
                    request = (HttpWebRequest)WebRequest.Create(headers["Location"]);
                    SetRequestDefaults();
                    HttpWebResponse redirectedResponse = (HttpWebResponse)request.GetResponse();
                    sessionID = request.RequestUri.Query.Replace("?", "");
                    resStream = redirectedResponse.GetResponseStream();
                    // return SendRequestTo(requestBytes,new Uri(headers["location"]),credential); 
                }
            }

            byte[] buffer = new byte[8192];
            StringBuilder stringBuilder = new StringBuilder();
            string tempString = null;
            int count = 0;
            do {
                // fill the buffer with data
                count = resStream.Read(buffer, 0, buffer.Length);
                // make sure we read some data
                if (count != 0) {
                    // translate from bytes to ASCII text
                    tempString = Encoding.ASCII.GetString(buffer, 0, count);
                    // continue building the string
                    stringBuilder.Append(tempString);
                }
            }

            while (count > 0); // any more data to read?

            string html = stringBuilder.ToString();
            WriteDebugHTML(html);
            return html;
        }

        public string SetCookies(ref Credentials credentials) {
            string result = null;
            string username = credentials.Username;
            string password = credentials.Password;

#warning TODO
            cookieContainer = new CookieContainer(); /*credentials.Cookies != null ? credentials.Cookies : string.NewStr;*/

            byte[] buffer = new byte[8192];
            string url = WoWAddonRefresh.Constants.URL_WoWInterface;
            request = (HttpWebRequest)HttpWebRequest.Create(url);

            SetRequestDefaults();
            /*
            <input name="next" value="" type="hidden">
            <input name="action" value="login" type="hidden">
            <input name="email" id="id_email" type="text">  
            <input id="id_password" name="password" maxlength="30" type="password">
            <input checked="checked" name="remember_me" id="id_remember_me" type="checkbox">
            <input value="Login" type="submit">
             */

            string postData = "remember_me=1&id_remember_me=1&action=login&email=" + username + "&password=" + password + "&id_email=" + username + "&id_password=" + password + "";
            UTF8Encoding encoding = new UTF8Encoding();
            byte[] data = encoding.GetBytes(postData);

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;
            Stream stream = request.GetRequestStream();
            stream.Write(data, 0, data.Length);
            stream.Close();

            response = (HttpWebResponse)request.GetResponse();

            Stream resStream = response.GetResponseStream();

            if (request.HaveResponse) {
                // headerCollection = response.Headers;

                foreach (Cookie cookie in response.Cookies) {
                    cookie.Expires = cookie.Expires.Date <= System.DateTime.Now.Date ? System.DateTime.Now.AddYears(1) : cookie.Expires;
                    cookie.Expired = false;
                    cookie.Discard = false;
                    cookieContainer.Add(cookie);
                }

#warning TODO
                credentials.Cookies = /*cookieContainer;*/ string.Empty;
                if (credentials.Headers == null) {
                    // credentials.Headers = new Headers();
                }
                else {
                    credentials.Headers = null; ;
                    //foreach (string key in headerCollection.Keys) {
                    //    Header header = new Header();
                    //    header.Key = key;
                    //    header.Value = headerCollection[key];
                    //}
                    // credentials.Headers.Add(header);
                }


                // Next is redirection
                if ((response.StatusCode == HttpStatusCode.Found) ||
                    (response.StatusCode == HttpStatusCode.Redirect) ||
                    (response.StatusCode == HttpStatusCode.Moved) ||
                    (response.StatusCode == HttpStatusCode.MovedPermanently)) {
                    // Get new location and call recursively
                    WebHeaderCollection headers = response.Headers;
                    request = (HttpWebRequest)WebRequest.Create(headers["Location"]);
                    SetRequestDefaults();
                    HttpWebResponse redirectedResponse = (HttpWebResponse)request.GetResponse();
                    sessionID = request.RequestUri.Query.Replace("?", "");
                    resStream = redirectedResponse.GetResponseStream();
                    // return SendRequestTo(requestBytes,new Uri(headers["location"]),credential); 
                }
            }

            StringBuilder stringBuilder = new StringBuilder();
            string tempString = null;
            int count = 0;
            do {
                // fill the buffer with data
                count = resStream.Read(buffer, 0, buffer.Length);
                // make sure we read some data
                if (count != 0) {
                    // translate from bytes to ASCII text
                    tempString = Encoding.ASCII.GetString(buffer, 0, count);
                    // continue building the string
                    stringBuilder.Append(tempString);
                }
            }

            while (count > 0); // any more data to read?

            string html = stringBuilder.ToString();
            int urlIndex = html.IndexOf(@"http://feeds.curse.com/favorites/");
            if (urlIndex > 0) {
                result = html.Substring(urlIndex, html.IndexOf("\"", urlIndex) - urlIndex);
            }
            else {
                result = null;
            }

            urlIndex = html.IndexOf(@"http://feeds.curse.com/favorites/", urlIndex + 1);
            if (urlIndex > 0) {
                result = html.Substring(urlIndex, html.IndexOf("\"", urlIndex) - urlIndex);
                LOGEDIN = true;
            }

            // print out page source 
            if (response.Cookies.Count == 0 && response.Headers.Count < 9 || result == null) {
                // string filename = "debug_login.html";
                string filename = "WoWAddonRefresh_loginError.html";
                StreamWriter writer = new StreamWriter(filename, false);
                writer.WriteLine(stringBuilder.ToString());
                writer.Flush();
                writer.Close();
                LOGEDIN = false;
            }

            return result;
        }

        public void Download(ref Addon addon, string tempFolderName, string message) {
            // GetAddonHTML(ref addon);
            string URL = addon.DownloadURL;

            if (URL == null) {
                return;
            }
            // restriction check before download
            DownloadSpan ds = new DownloadSpan();
            downloadSpans.Add(ds);
            foreach (DownloadSpan downloadSpan in downloadSpans) {
                // restriction register addon download
                if (downloadSpan.Active) downloadSpan.addons.Add(addon);

                TimeSpan needWait = downloadSpan.NeedWait;
                while ((needWait.Ticks) > 0) {
                    needWait = downloadSpan.NeedWait;
                    mainForm.SetStatus("Max downloads count (" + DownloadSpan.RestrictionCount.ToString() + ") per " + (DownloadSpan.RestrictionSpan.Seconds.ToString()) + " sec reached, waiting " + decimal.Round((decimal)needWait.TotalSeconds, 0).ToString() + " sec...");
                    Thread.Sleep(new TimeSpan(0, 0, 0, 0, 500));
                }
            }

            request = (HttpWebRequest)HttpWebRequest.Create(Constants.URL_WoWInterface_Download + URL);
            request.CookieContainer = cookieContainer;
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            string filename = null;
            string error_text = "Error wile downloadding Addon " + addon.Name + "\npossible errors:\n1) You created to many download connections (5 is max allowed)\n2) You made too many (more than 50) downloads in 30 seconds\nsolution:\n3) Just a broken link\n\nSolution:\ntry again later or change your ip";
            bool error = false;

            if (response.ContentType == "text/html") {
                if (response.ResponseUri.AbsolutePath == "/error_downdoesnotexist.php") {
                    error = mainForm.ShowError("Server reported that addon " + addon.Name + " download not exist, please try to download it manualy");
                }
                else {
                    error = mainForm.ShowError(error_text);
                    Stream stream = response.GetResponseStream();
                    FileStream fileStream = new FileStream("lasterror.html", FileMode.OpenOrCreate, FileAccess.Write);

                    byte[] buffer = new byte[100000];
                    int bytesToRead = (int)buffer.Length;
                    int bytesReaded = 0;
                    do {
                        bytesReaded = stream.Read(buffer, 0, bytesToRead);
                        if (bytesReaded > 0) {
                            fileStream.Write(buffer, 0, bytesReaded);
                        }
                    }
                    while (bytesReaded > 0);

                    stream.Close();
                    fileStream.Close();
                }
            }
            else if (response.ContentType == "application/octet-stream" || response.ContentType == "application/zip") {
                filename = GetFilename(response);
                // string realURL = response.ResponseUri.AbsolutePath;
                // filename = realURL.Substring(realURL.LastIndexOf("/") + 1);
                addon.FileName = filename;
            }
            else {
                error = mainForm.ShowError(error_text);
            }

            if (filename == null && !error) {
                error = mainForm.ShowError(error_text);
            }

            if (!error) {
                Stream stream = response.GetResponseStream();

                FileStream fileStream = new FileStream(tempFolderName + "/" + filename, FileMode.OpenOrCreate, FileAccess.Write);

                byte[] buffer = new byte[100000];
                int bytesToRead = (int)buffer.Length;
                int bytesReaded = 0;
                int bytesTotalToRead = (int)(response.ContentLength);
                int bytesTotalReaded = 0;
                do {
                    bytesReaded = stream.Read(buffer, 0, bytesToRead);
                    if (bytesReaded > 0) {
                        fileStream.Write(buffer, 0, bytesReaded);
                    }
                    bytesTotalReaded += bytesReaded;
                    mainForm.SetStatus(message + " " + GetProcent(bytesTotalToRead, bytesTotalReaded) + "%");
                }
                while (bytesReaded > 0);

                stream.Close();
                fileStream.Close();
            }
        }

        private int GetProcent(int bytesToRead, int bytesReaded) {
            return (bytesReaded / (bytesToRead / 100));
        }

    }
}
